<template>
  <n-modal
    :show="props.visible"
    preset="card"
    :title="props.data?.roleId ? '修改角色' : '添加角色'"
    style="width: 550px"
    @after-enter="handleOpen"
    @close="handleClose"
  >
    <n-spin :show="spinLoading">
      <n-form ref="formRef" :model="form" label-placement="left" :label-width="90" :rules="rules">
        <n-form-item label="角色名称" path="roleName">
          <n-input v-model:value="form.roleName" placeholder="请输入角色名称" clearable />
        </n-form-item>

        <n-form-item label="权限字符" path="roleKey">
          <n-input v-model:value="form.roleKey" placeholder="请输入权限字符" clearable />
        </n-form-item>

        <n-form-item label="角色顺序" path="roleSort">
          <n-input-number
            class="w-full"
            v-model:value="form.roleSort"
            :min="0"
            placeholder="请输入角色顺序"
            clearable
          />
        </n-form-item>

        <n-form-item label="状态">
          <n-radio-group v-model:value="form.status">
            <template v-for="item in dicts.sys_normal_disable" :key="item.value">
              <n-radio :value="item.value">{{ item.label }}</n-radio>
            </template>
          </n-radio-group>
        </n-form-item>

        <n-form-item class="flex-col" label="菜单权限" path="roleSort" label-placement="left">
          <div class="pt-[5px] w-full">
            <n-space>
              <n-checkbox v-model:checked="expandCollapse">展开/折叠</n-checkbox>
              <n-checkbox v-model:checked="selectDeselect">全选/取消全选</n-checkbox>
              <n-checkbox v-model:checked="form.menuCheckStrictly">父子级关联</n-checkbox>
            </n-space>
            <n-tree
              class="border border-[#e0e0e6] mt-[5px]"
              key-field="id"
              :data="treeData"
              :default-expanded-keys="[]"
              expand-on-click
              checkable
              :cascade="form.menuCheckStrictly"
              :expanded-keys="expandedKeys"
              :checked-keys="form.menuIds"
              @update:expanded-keys="handleExpandedKeys"
              @update:checked-keys="handleCheckedKeys"
            >
            </n-tree>
          </div>
        </n-form-item>

        <n-form-item label="备注" path="remark">
          <n-input v-model:value="form.remark" type="textarea" placeholder="请输入内容" clearable />
        </n-form-item>
      </n-form>
    </n-spin>

    <template #footer>
      <n-space justify="end">
        <n-button @click="handleClose">取消</n-button>
        <n-button type="primary" @click="submitCallback" :loading="loading" :disabled="loading">
          确定
        </n-button>
      </n-space>
    </template>
  </n-modal>
</template>

<script lang="ts" setup>
import { useDict } from '@/hooks/useDict';
import { useForm } from '@/hooks/useForm';
import { useMessage } from 'naive-ui';
import { computed, ref, watch } from 'vue';
import { getMenuTree, getRoleMenuTree } from '@/apis/system/menu';
import { addRole, getRole, updateRole } from '@/apis/system/role';
import { getAllNodeKeys } from '@/utils';

const emits = defineEmits(['close']);
const props = defineProps<{ visible: boolean; data: any }>();
const data = computed(() => props.data);
const loading = ref(false);
const spinLoading = ref(false);
const message = useMessage();
const expandCollapse = ref(false);
const selectDeselect = ref(false);
const expandedKeys = ref([]);
// 获取字典：状态
const { dicts } = useDict('sys_normal_disable');
// 菜单tree data
const treeData = ref<any>([]);
// 表单
const { form, formRef, reset, setForm, validate } = useForm({
  roleId: null,
  roleName: null,
  roleKey: null,
  roleSort: null,
  status: '0',
  remark: null,
  menuIds: [],
  menuCheckStrictly: false, // 父子级关联
});
// 校验规则
const rules = ref({
  userName: [
    { required: true, message: '用户名称不能为空' },
    {
      min: 2,
      max: 20,
      message: '用户名称长度必须介于 2 和 20 之间',
      trigger: 'blur',
    },
  ],
  roleName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
  password: [
    { required: true, message: '用户密码不能为空', trigger: 'blur' },
    {
      min: 5,
      max: 20,
      message: '用户密码长度必须介于 5 和 20 之间',
      trigger: 'blur',
    },
  ],
});

/**
 * 监听全选、取消全选
 */
watch(
  () => selectDeselect.value,
  (val) => {
    if (val) {
      // 全选
      form.menuIds = getAllNodeKeys(treeData.value) as any;
    } else {
      // 取消全选
      form.menuIds = [];
    }
  },
);

// 打开弹窗回调
const handleOpen = async () => {
  spinLoading.value = true;
  if (data.value?.roleId) {
    const { roleId } = data.value;

    const res: any = await getRole(roleId);
    if (res.code == 200) {
      setForm(res.data);
    }

    const treeRes: any = await getRoleMenuTree(roleId);
    if (treeRes.code == 200) {
      treeData.value = treeRes.data.menus;
      form.menuIds = treeRes.data.checkedKeys;
    }
  } else {
    const res: any = await getMenuTree();
    if (res.code == 200) {
      treeData.value = res.data;
    }
  }

  spinLoading.value = false;
};

// 关闭弹窗回调
const handleClose = (needRefresh = false) => {
  reset();
  emits('close', { needRefresh });
};

// 保存
const submitCallback = async (e: MouseEvent) => {
  e.preventDefault();
  const errors = await validate();
  if (errors) return;

  loading.value = true;

  try {
    let res: any;
    if (data.value?.roleId) {
      res = await updateRole(form);
    } else {
      res = await addRole(form);
    }
    if (res.code == 200) {
      message.success(data.value?.roleId ? '修改成功' : '添加成功');
      handleClose(true);
    }
  } catch (error) {
  } finally {
    loading.value = false;
  }
};

// 展开/折叠
function handleExpandedKeys(keys: any) {
  expandedKeys.value = keys;
}

// 节点选中时，获取所有选中节点的keys
function handleCheckedKeys(keys: any) {
  form.menuIds = keys;
}
</script>

<style lang="less" scoped></style>
